//################################################################################
// MIT License
// Copyright (c) 2024 ZhangYihua
//
// Change Logs:
// Date           Author       Notes
// 2020-10-18     ZhangYihua   first version
//
// Description  : 
//################################################################################

`ifndef PUBLIC_HEAD_SV_FILE
`define PUBLIC_HEAD_SV_FILE

interface vld_rdy_src_it #(DATA_BW=18, INFO_BW=1, MAX_LEN=100)
                          (input logic clk);
    logic vld=0;
    logic sop=0;
    logic eop=0;
    logic [DATA_BW-1:0] data;
    logic [INFO_BW-1:0] info;
    logic rdy;

    task automatic src_tx_t;
        input integer gap;
        input integer len;
        input logic [INFO_BW-1:0] info_i;
        ref   logic [DATA_BW-1:0] data_i[MAX_LEN-1:0];
        integer cnt;

        cnt  = 1;

        repeat(gap) begin
            @(posedge clk);
        end

        while(cnt<=len) begin
            vld  <=`U_DLY 1;
            sop  <=`U_DLY (cnt==1  ) ? 1 : 0;
            eop  <=`U_DLY (cnt==len) ? 1 : 0;

            data <=`U_DLY data_i[cnt-1];
            info <=`U_DLY info_i;

            @(posedge clk);
            while(!rdy) begin
                @(posedge clk);
            end
            cnt = cnt+1;
        end
        vld  <=`U_DLY 0;
        eop  <=`U_DLY 0;
        data <=`U_DLY {DATA_BW{1'bx}};
        info <=`U_DLY {INFO_BW{1'bx}};
    endtask
endinterface

interface vld_rdy_dst_it #(DATA_BW=18, INFO_BW=1, MAX_LEN=100)
                          (input logic clk);
    logic vld;
    logic sop;
    logic eop;
    logic [DATA_BW-1:0] data;
    logic [INFO_BW-1:0] info;
    logic rdy=0;

    task automatic dst_rx_t;
        input integer rdy_pov;      // range [1:100}
        output integer len_o;
        output logic [INFO_BW-1:0] info_o;
        ref    logic [DATA_BW-1:0] data_o[MAX_LEN-1:0];
        integer cnt;
        logic   done;

        cnt  = 1;
        done = 0;

        while(!done) begin
            @(posedge clk);
            rdy <=`U_DLY ($urandom_range(1, 100)<=rdy_pov) ? 1 : 0;
            while((vld&rdy)==0) begin
                @(posedge clk);
                rdy <=`U_DLY ($urandom_range(1, 100)<=rdy_pov) ? 1 : 0;
            end

            if (cnt==1) begin
                info_o = info;
            end

            data_o[cnt-1] = data;

            done = eop;
            cnt  = cnt+1;
        end
        len_o = cnt;
    endtask
endinterface

interface req_ack_src_it #(INFO_BW=18, RESP_BW=1)
                          (input logic clk);
    logic req=0;
    logic nfr=0;
    logic ack;
    logic [INFO_BW-1:0] info;
    logic [RESP_BW-1:0] resp;

    task src_req_t;
        input integer gap;
        input logic nfr_i;
        input logic [INFO_BW-1:0] info_i;

        repeat(gap) begin
            @(posedge clk);
        end

        begin
            req  <=`U_DLY 1;
            nfr  <=`U_DLY nfr_i;
            info <=`U_DLY info_i;

            @(posedge clk);
            while(!ack) begin
                @(posedge clk);
            end
        end
        req  <=`U_DLY 0;
        nfr  <=`U_DLY 0;
        info <=`U_DLY {INFO_BW{1'bx}};
    endtask
endinterface

interface req_ack_dst_it #(INFO_BW=18, RESP_BW=1)
                          (input logic clk);
    logic req;
    logic nfr;
    logic ack=0;
    logic [INFO_BW-1:0] info;
    logic [RESP_BW-1:0] resp;

    task info_rx_t;
        output logic nfr_o;
        output logic [INFO_BW-1:0] info_o;

        begin
            @(posedge clk);
            while(!req) begin
                @(posedge clk);
            end
            nfr_o  = nfr;
            info_o = info;
        end
    endtask

    task dst_ack_t;
        input integer dly;
        input logic [RESP_BW-1:0] resp_i;

        repeat(dly) begin
            @(posedge clk);
        end

        begin
            ack  <=`U_DLY 1'b1;
            resp <=`U_DLY resp_i;
            @(posedge clk);
        end

        ack  <=`U_DLY 1'b0;
        resp <=`U_DLY {RESP_BW{1'bx}};
    endtask

    a_info_stable: assert property (@(posedge clk)
        (req&$stable(req)&(!$past(ack))|-> $stable(info))
    ) else begin
        $error("info is not stable.");
    end
endinterface

interface rab_it #(AW = 12, DW = 32) (input logic clk);
    logic en=0;
    logic wr=0;
    logic [AW-1:0] addr;
    logic [DW-1:0] wdat;
    logic [DW-1:0] rdat;
    logic busy;

    task wr_reg_t;
        input integer gap;
        input logic [AW-1:0] addr_i;
        input logic [DW-1:0] data_i;

        repeat(gap) begin
            @(posedge clk);
        end

        en <=`U_DLY 1'b1;
        wr <=`U_DLY 1'b1;
        addr <=`U_DLY addr_i;
        wdat <=`U_DLY data_i;
        @(posedge clk);
        en <=`U_DLY 1'b0;
        @(posedge clk);
        while(busy==1'b1) begin
            @(posedge clk);
        end
    endtask

    task rd_reg_t;
        input integer gap;
        input logic [AW-1:0] addr_i;
        output logic [DW-1:0] data_o;

        repeat(gap) begin
            @(posedge clk);
        end

        en <=`U_DLY 1'b1;
        wr <=`U_DLY 1'b0;
        addr <=`U_DLY addr_i;
        @(posedge clk);
        en <=`U_DLY 1'b0;
        @(posedge clk);
        while(busy==1'b1) begin
            @(posedge clk);
        end
        data_o = rdat;
    endtask
endinterface

`endif
